package imp

import (
	sqlc "bgs/db/sqlc"
	syncGrpc "bgs/grpc/gen/service/sync"
	"bgs/grpc/gen/shared/message"
	"bgs/util"
	"context"
	"database/sql"
	pg "github.com/lib/pq"
)

/****************************************************************************************/
/*                               sync_mapping entity of helper                          */
/****************************************************************************************/

func transformSyncRemoteEntityToPb(remote sqlc.SyncRemote) *syncGrpc.SyncRemoteEntity {
	return &syncGrpc.SyncRemoteEntity{
		Id:        remote.ID,
		SyncId:    remote.SyncID,
		RemoteObj: remote.RemoteObj,
		RemotePk:  remote.RemotePk,
		Data:      string(remote.Data),
	}
}

func mapSyncRemoteEntityToPb(list []sqlc.SyncRemote, f func(sqlc.SyncRemote) *syncGrpc.SyncRemoteEntity) []*syncGrpc.SyncRemoteEntity {
	r := make([]*syncGrpc.SyncRemoteEntity, len(list))
	for i, item := range list {
		r[i] = f(item)
	}
	return r
}

/****************************************************************************************/
/*                               sync_remote entity of cmd                              */
/****************************************************************************************/

// CopySyncRemote 批量插入远程对象
func (s *SyncAPIService) CopySyncRemote(ctx context.Context, req *syncGrpc.CopySyncRemoteRequest) (res *syncGrpc.CopySyncRemoteResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("sync_remoteImp->CopySyncRemote:%v", req)

	res = &syncGrpc.CopySyncRemoteResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	var total int64
	query := pg.CopyIn("sync_remotes", "sync_id", "remote_obj", "remote_pk", "data")
	slog.Infof("query=>%s", query)
	err = s.dao.NewTxRunner().StmtExecTx(ctx, query, func(s *sql.Stmt) (err error) {
		for _, item := range req.SyncRemotes {
			_, err = s.ExecContext(ctx, item.SyncId, item.RemoteObj, item.RemotePk, item.Data)
			if err != nil {
				return err
			}
		}
		err = s.Close()
		if err != nil {
			panic(err)
		}
		total = int64(len(req.SyncRemotes))
		return
	})
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	return
}

/****************************************************************************************/
/*                               sync_remote entity of query                            */
/****************************************************************************************/

// GetSyncRemoteBySyncIDAndRemotePk 获取单个远程同步对象
func (s *SyncAPIService) GetSyncRemoteBySyncIDAndRemotePk(ctx context.Context, req *syncGrpc.GetSyncRemoteBySyncIDAndRemotePkRequest) (res *syncGrpc.GetSyncRemoteBySyncIDAndRemotePkResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("syncImp->GetSyncRemoteBySyncIDAndRemotePk:%v", req)
	res = &syncGrpc.GetSyncRemoteBySyncIDAndRemotePkResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	arg := sqlc.GetSyncRemoteBySyncIDAndRemotePkParams{
		SyncID:   req.SyncId,
		RemotePk: req.RemotePk,
	}
	syncRemote, sqlErr := s.dao.Q.GetSyncRemoteBySyncIDAndRemotePk(ctx, arg)
	if sqlErr != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    util.Int32IfThenElse(sql.ErrNoRows == sqlErr, 404, 400),
			Msg:     sqlErr.Error(),
		}
		return
	}
	res.SyncRemote = transformSyncRemoteEntityToPb(syncRemote)
	return
}

// ListSyncRemotesBySyncID 分页获取多个同步映射
func (s *SyncAPIService) ListSyncRemotesBySyncID(ctx context.Context, req *syncGrpc.ListSyncRemotesBySyncIDRequest) (res *syncGrpc.ListSyncRemotesBySyncIDResponse, err error) {
	slog := s.NewContextLogger(ctx)
	slog.Infof("sync_remoteImp->ListSyncRemotesBySyncID:%v", req)

	res = &syncGrpc.ListSyncRemotesBySyncIDResponse{
		OpRet: &message.OperationResult{
			Success: true,
			Code:    0,
		},
	}
	total, err := s.dao.Q.CountSyncRemotesBySyncID(ctx, req.SyncId)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}

	if total == 0 {
		// 不用继续调用listfunc
		return
	}

	arg := sqlc.ListSyncRemotesBySyncIDParams{
		Limit:  req.Limit,
		Offset: req.Offset,
		SyncID: req.SyncId,
	}
	syncMappings, err := s.dao.Q.ListSyncRemotesBySyncID(ctx, arg)
	if err != nil {
		res.OpRet = &message.OperationResult{
			Success: false,
			Code:    400,
			Msg:     err.Error(),
		}
		return
	}
	res.Total = total
	res.SyncRemotes = mapSyncRemoteEntityToPb(syncMappings, transformSyncRemoteEntityToPb)
	return
}
